#region License

// This file is part of Grawlix.
// 
// Grawlix is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
// Grawlix is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with Grawlix.  If not, see
// <http://www.gnu.org/licenses/>.

#endregion

using System;

namespace Grawlix.Services.Resources
{
	/// <summary>
	/// A simple tuple containing resource state and failure
	/// status.
	/// </summary>
	[Serializable]
	public struct ResourceState : IEquatable<ResourceState>
	{
		/// <summary>
		/// Whether the load was a failure.
		/// </summary>
		private bool _loadFailed;

		/// <summary>
		/// The loaded state object, or null.
		/// </summary>
		private object _stateData;

		/// <summary>
		/// Initializes a new instance of the 
		/// <see cref="ResourceState"/> struct.
		/// </summary>
		/// <param name="stateData">The state object.</param>
		/// <param name="loadFailed">if set to <c>true</c>, the load
		/// failed.</param>
		public ResourceState(object stateData, bool loadFailed)
		{
			_stateData = stateData;
			_loadFailed = loadFailed;
		}

		/// <summary>
		/// Gets a value indicating whether the load failed.
		/// </summary>
		/// <value><c>true</c> if the load failed; otherwise, 
		/// <c>false</c>.</value>
		public bool LoadFailed
		{
			get { return _loadFailed; }
			set { _loadFailed = value; }
		}

		/// <summary>
		/// Gets the state object.
		/// </summary>
		/// <value>The state object data.</value>
		public object StateData
		{
			get { return _stateData; }
			set { _stateData = value; }
		}

		/// <summary>
		/// Indicates whether the current object is equal to another
		/// object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.
		/// </param>
		/// <returns>
		/// true if the current object is equal to the 
		/// <paramref name="other"/> parameter; otherwise, false.
		/// </returns>
		public bool Equals(ResourceState other)
		{
			return other._loadFailed.Equals(_loadFailed) &&
			       Equals(other._stateData, _stateData);
		}

		/// <summary>
		/// Indicates whether this instance and a specified object are
		/// equal.
		/// </summary>
		/// <param name="obj">Another object to compare to.</param>
		/// <returns>
		/// true if <paramref name="obj"/> and this instance are the
		/// same type and represent the same value; otherwise, false.
		/// </returns>
		public override bool Equals(object obj)
		{
			if (obj.GetType() != typeof(ResourceState))
				return false;
			return Equals((ResourceState)obj);
		}

		/// <summary>
		/// Returns the hash code for this instance.
		/// </summary>
		/// <returns>
		/// A 32-bit signed integer that is the hash code for this
		/// instance.
		/// </returns>
		public override int GetHashCode()
		{
			unchecked
			{
				return (_loadFailed.GetHashCode() * 397) ^
				       (_stateData != null
				        	? _stateData.GetHashCode()
				        	: 0);
			}
		}

		/// <summary>
		/// Compares two <see cref="ResourceState"/> structures for
		/// equality.
		/// </summary>
		/// <param name="left">The left-hand side of the comparison.
		/// </param>
		/// <param name="right">The right-hand side of the comparison.
		/// </param>
		/// <returns><c>true</c> if equal; else <c>false</c>.</returns>
		public static bool operator ==(
			ResourceState left, ResourceState right)
		{
			return left.Equals(right);
		}

		/// <summary>
		/// Compares two <see cref="ResourceState"/> structures for
		/// inequality.
		/// </summary>
		/// <param name="left">The left-hand side of the comparison.
		/// </param>
		/// <param name="right">The right-hand side of the comparison.
		/// </param>
		/// <returns><c>false</c> if equal; else <c>tr</c>.</returns>
		public static bool operator !=(
			ResourceState left, ResourceState right)
		{
			return !left.Equals(right);
		}
	}
}